package com.boyinet.imesh2json.netty.handler

import cn.hutool.core.date.DateUtil
import com.boyinet.imesh2json.netty.client.TransformClient
import com.boyinet.imesh2json.netty.policy.RetryPolicy
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.channel.EventLoop
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.concurrent.TimeUnit


@ChannelHandler.Sharable
class ReConnectHandler(private var transformClient: TransformClient) : ChannelInboundHandlerAdapter() {

    private var retries = 0

    private var retryPolicy: RetryPolicy? = null

    private val log: Logger = LoggerFactory.getLogger(ReConnectHandler::class.java)

    override fun channelActive(ctx: ChannelHandlerContext?) {
        super.channelActive(ctx)
        log.info("连接成功 At:${DateUtil.now()}")
        retries = 0
        ctx?.fireChannelActive()
    }

    override fun channelInactive(ctx: ChannelHandlerContext?) {
        if (retries == 0) {
            log.info("连接断开 At:${DateUtil.now()}")
            ctx!!.close()
        }

        val allowRetry: Boolean = getRetryPolicy()!!.allowRetry(retries)
        if (allowRetry) {
            val sleepTimeMs: Long = getRetryPolicy()!!.getSleepTimeMs(retries)
            log.info(
                String.format(
                    "Try to reconnect to the server after %dms. Retry count: %d.",
                    sleepTimeMs,
                    ++retries
                )
            )
            val eventLoop: EventLoop = ctx!!.channel().eventLoop()
            eventLoop.schedule({
                log.info("Reconnecting ...")
                transformClient.connect()
            }, sleepTimeMs, TimeUnit.MILLISECONDS)
        } else {
            log.info("重连已被禁用")
        }
        ctx!!.fireChannelInactive()
    }

    private fun getRetryPolicy(): RetryPolicy? {
        if (this.retryPolicy == null) {
            this.retryPolicy = transformClient.retryPolicy
        }
        return this.retryPolicy
    }
}